package tjs.study.mini.mybatismini.config.proxy;


import tjs.study.mini.mybatismini.config.annotion.MiniParam;
import tjs.study.mini.mybatismini.config.annotion.MiniSelect;

import javax.sql.DataSource;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Mapper的代理切面类
 * 对标以下类
 *
 * @author nicky
 * @date 2021/9/6 上午11:24
 * @see org.apache.ibatis.binding.MapperProxy
 */
public class MapperProxy implements InvocationHandler, Serializable {
    private DataSource dataSource;

    public MapperProxy(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Connection connection = dataSource.getConnection();
        System.out.println("编译mapper.xml对应方法[" + method.getName() + "]的sql...");

        String sql = findSql(method);
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        formatSql(method, args, preparedStatement);

        System.out.println("访问数据库...");
        ResultSet resultSet = preparedStatement.executeQuery();

        return formatResult(method, resultSet);
    }

    private void formatSql(Method method, Object[] args, PreparedStatement preparedStatement) throws SQLException {
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Annotation paramAnnotation = parameterAnnotations[i][0];
            if (paramAnnotation instanceof MiniParam) {
                preparedStatement.setObject(i + 1, args[i]);
            }
        }
    }

    private String findSql(Method method) {
        MiniSelect miniSelect = method.getAnnotation(MiniSelect.class);
        String sql = miniSelect.value()[0];
        sql = sql.replaceAll("#\\{.*\\}", " ? ");
        return sql;
    }

    private Object formatResult(Method method, ResultSet resultSet) throws InstantiationException, IllegalAccessException, SQLException {
        Class resultClass = method.getReturnType();
        Field[] fields = resultClass.getDeclaredFields();
        Object resultVal = resultClass.newInstance();
        while (resultSet.next()) {
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    Object fieldVal = resultSet.getObject(field.getName());
                    field.set(resultVal, fieldVal);//todo id类型不对，反射不回去
                } catch (Exception ex) {
                }
            }
        }
        return resultVal;
    }
}
